package com.vecspace.framework.sysdata.service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.vecspace.cache.InMemoryCache;
import com.vecspace.data.model.DataLockState;
import com.vecspace.framework.sysdata.dao.SysDataLockDao;
import com.vecspace.framework.sysdata.dao.SysDataLogDao;
import com.vecspace.framework.sysdata.dao.SysDataTableDao;
import com.vecspace.framework.sysdata.pojo.DataLog;
import com.vecspace.security.model.LoginContext;
import com.vecspace.utils.Convert;

@Service("sys_data_service")
public class SysDataService {
	/**
	 * 
	 * @param tableName 表名
	 * @param schema 表schema，可以为空
	 * @param masterId 父表记录Id；-1表示对本表所有记录的锁定状态。
	 * @param lockTable 被锁定的表，可以为空，表示锁定主表自己
	 * @return
	 * @throws Exception 
	 */
	public int getLockState(String masterTableName, String schema, Long masterId, String lockTable) throws Exception {
		Long tableId = getTableIdCachePrior(masterTableName, schema, false);
		return dataLockDao.getLockState(tableId, masterId, lockTable);
	}
	
	/**
	 * 
	 * @param tableName 表名
	 * @param schema 表schema，可以为空
	 * @param masterId 父表记录Id；-1表示对本表所有记录的锁定状态。
	 * @param lockTable 被锁定的表，可以为空，表示锁定主表自己
	 * @param lockTable 锁定状态，参考 DataLockState
	 * @return
	 * @throws Exception 
	 */
	public int changeLockState(String masterTableName, String schema, Long masterId, String lockTable, int lockState) throws Exception {
		Long tableId = getTableIdCachePrior(masterTableName, schema, true);
		dataLockDao.changeLockState(tableId, masterId, lockTable, lockState);
		return lockState;
	}
	
	public List<DataLog> getLogs(String tableName, String schema, String columnName, Long dataId) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		List<DataLog> logs = dataLogDao.getLogs(dataId, columnId);
		return logs;
	}
	
	public void addLog(String tableName, String schema, String columnName, Long dataId, String oldValue, String newValue, Long batchNum) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		Long userId = LoginContext.getUserId();
		dataLogDao.addLog(tableId, dataId, columnId, oldValue, newValue, batchNum, userId);
	}

	public void addClobLog(String tableName, String schema, String columnName, Long dataId, String oldValue, String newValue, Long batchNum) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		Long userId = LoginContext.getUserId();
		dataLogDao.addClobLog(tableId, dataId, columnId, oldValue, newValue, batchNum, userId);
	}

	public void addDateLog(String tableName, String schema, String columnName, Long dataId, LocalDate oldValue, LocalDate newValue, Long batchNum) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		Long userId = LoginContext.getUserId();
		dataLogDao.addDateLog(tableId, dataId, columnId, oldValue, newValue, batchNum, userId);
	}
	
	public void addDateTimeLog(String tableName, String schema, String columnName, Long dataId, LocalDateTime oldValue, LocalDateTime newValue, Long batchNum) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		Long userId = LoginContext.getUserId();
		dataLogDao.addDateTimeLog(tableId, dataId, columnId, oldValue, newValue, batchNum, userId);
	}

	public void addNumberLog(String tableName, String schema, String columnName, Long dataId, Object oldValue, Object newValue, Long batchNum) throws Exception {
		Long tableId = this.getTableIdCachePrior(tableName, schema, true);
		Long columnId = this.getColumnIdCachePrior(tableId, columnName, true);
		Long userId = LoginContext.getUserId();
		dataLogDao.addNumberLog(tableId, dataId, columnId, oldValue, newValue, batchNum, userId);
	}
	
	public Long getTableIdCachePrior(String tableName, String schema, boolean autoInsert) throws Exception {
		tableName = tableName.trim().toUpperCase();
		String cacheName = "TABLES";
		if(schema == null)schema="";
		schema = schema.trim().toUpperCase();
		String key = String.format("%s-%s", tableName, schema);
		Long tableId = (Long)InMemoryCache.DEFAULT().get(cacheName, key);
		if(tableId == null) {
			synchronized (key) {
				tableId = (Long)InMemoryCache.DEFAULT().get(cacheName, key);
				if(tableId == null) {
					tableId = tableDao.getTableId(tableName, schema, autoInsert);
					if(tableId != null && tableId != 0) {
						InMemoryCache.DEFAULT().put(cacheName, key, tableId);
					}
				}
			}
		}
		return tableId;
	}
	
	public Long getColumnIdCachePrior(Long tableId, String columnName, boolean autoInsert) throws Exception {
		String cacheName = "TABLE-COLUMNS";
		String key = String.format("%s-%s", tableId, columnName);
		Long columnId = (Long)InMemoryCache.DEFAULT().get(cacheName, key);
		if(columnId == null) {
			synchronized (key) {
				columnId = (Long)InMemoryCache.DEFAULT().get(cacheName, key);
				if(columnId == null) {
					columnId = tableDao.getColumnId(tableId, columnName, autoInsert);
					if(columnId != null && columnId != 0) {
						InMemoryCache.DEFAULT().put(cacheName, key, columnId);
					}
				}
			}
		}
		return columnId;
	}
	 /** property **/
    @Autowired
    private SysDataLockDao dataLockDao;
	
	@Autowired
    private SysDataTableDao tableDao;
	
	@Autowired
    private SysDataLogDao dataLogDao;
}
